#include "dcmwatcher.h"

#include "global.h"
#include "dirwatch.h"
#include "dispatch.h"
#include "dispatch.h"
#include "parsedcm.h"
#include "scanthread.h"
#include "verifydcm.h"

#include <QFile>
#include <QTextStream>
#include <QCoreApplication>
#include <QSqlDatabase>
#include <QSqlRecord>
#include <QSqlError>
#include <QSqlQuery>
#include <QDebug>

DcmWatcher::DcmWatcher(QObject *parent) :
    m_dispatch(0),
    m_verify(0),
    m_parse(0),
    QObject(parent)
{
}

DcmWatcher::~DcmWatcher()
{
}

void DcmWatcher::setupDb()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "DCMWATCH");
    db.setDatabaseName(QCoreApplication::applicationDirPath()+"/"SQLITE_DB_NAME);
    if (db.open()) {
        QSqlQuery q(db);
        q.exec("CREATE TABLE IF NOT EXISTS status_t (id INT PRIMARY KEY NOT NULL, status VARCHAR(128))");
        q.exec("CREATE TABLE IF NOT EXISTS study_t (study_iuid VARCHAR(128) PRIMARY KEY NOT NULL,"
                "pati_id VARCHAR(64), pati_name VARCHAR(64), pati_sex VARCHAR(6),"
                "pati_age VARCHAR(6), acc_num VARCHAR(64), modality VARCHAR(6), body_part VARCHAR(256),"
                "study_time DATETIME NOT NULL, request_time DATETIME,"
                "last_status_time DATETIME, status_id_fk INT DEFAULT 0,"
                "sync_db_f TINYINT DEFAULT 0, rm_f TINYINT DEFAULT 0,"
                "FOREIGN KEY(status_id_fk) REFERENCES status_t(id))");
        q.exec("CREATE INDEX IF NOT EXISTS IX_study_studydate ON study_t(study_time)");
        q.exec("CREATE TABLE IF NOT EXISTS image_t (image_iuid VARCHAR(128) PRIMARY KEY NOT NULL,"
                "image_cuid VARCHAR(128), series_iuid VARCHAR(128), study_iuid_fk VARCHAR(128) NOT NULL,"
                "image_time DATETIME, file_path TEXT, sync_file_f TINYINT DEFAULT 0,"
                "sync_db_f TINYINT DEFAULT 0, rm_f TINYINT DEFAULT 0,"
                "FOREIGN KEY(study_iuid_fk) REFERENCES study_t(study_iuid))");
        q.exec("CREATE INDEX IF NOT EXISTS IX_image_imagetime ON image_t(image_time)");
        q.exec("CREATE TABLE report_t (report_iuid VARCHAR(128) PRIMARY KEY NOT NULL,"
                "report_cuid VARCHAR(128), series_iuid VARCHAR(128), study_iuid_fk VARCHAR(128),"
                "features TEXT, diagnosis TEXT, report_phy VARCHAR(64), report_time DATETIME,"
                "verify_phy VARCHAR(64), verify_time DATETIME, review_phy VARCHAR(64), review_time DATETIME,"
                "sync_db_f TINYINT DEFAULT 0, rm_f TINYINT DEFAULT 0,"
                "FOREIGN KEY(study_iuid_fk) REFERENCES study_t(study_iuid))");

        QStringList statusList;
        statusList << tr("Pending") << tr("Uploading") << tr("Consulting") << tr("Consulted") << tr("Reviewing") << tr("Reviewed");
        for (int i = 0; i < statusList.size(); ++i) {
            q.prepare("INSERT INTO status_t VALUES(?,?)");
            q.addBindValue(i);
            q.addBindValue(statusList.at(i));
            q.exec();
        }

    } else {
        qCritical() << tr("Open database failed: ") << db.lastError().text();
    }
}

void DcmWatcher::startDeamon()
{
    m_dispatch = new Dispatch;
    QThread *t = new QThread;
    m_dispatch->moveToThread(t);
    connect(t, SIGNAL(finished()), m_dispatch, SLOT(deleteLater()));
    connect(t, SIGNAL(finished()), t, SLOT(deleteLater()));
    t->start();
    m_verify = new VerifyDcm;
    t = new QThread;
    m_verify->moveToThread(t);
    connect(this, SIGNAL(startVerify()), m_verify, SLOT(fetchFile()));
    connect(t, SIGNAL(finished()), m_verify, SLOT(deleteLater()));
    connect(t, SIGNAL(finished()), t, SLOT(deleteLater()));
    t->start();
    m_parse = new ParseDcm;
    t = new QThread;
    m_parse->moveToThread(t);
    connect(this, SIGNAL(startParse()), m_parse, SLOT(fetchFile()));
    connect(m_dispatch, SIGNAL(fileRemoved(QString)), m_parse, SLOT(onFileRemoved(QString)));
    connect(m_dispatch, SIGNAL(fileRenamed(QString,QString)), m_parse, SLOT(onFileRenamed(QString,QString)));
    connect(t, SIGNAL(finished()), m_parse, SLOT(deleteLater()));
    connect(t, SIGNAL(finished()), t, SLOT(deleteLater()));
    t->start();

    emit startVerify();
    emit startParse();
}

void DcmWatcher::readDirs()
{
    QFile ini(QCoreApplication::applicationDirPath()+"/"DCM_SCAN_DIR_LIST_FILE);
    if (ini.open(QIODevice::ReadOnly|QIODevice::Text)) {
        QTextStream in(&ini);
        while (!in.atEnd()) {
            QString dir = in.readLine();
            if (!(dir.isEmpty() || dir.startsWith("#"))) {
                dir.replace("\\", "/");
                ScanThread *st = new ScanThread(dir);
                connect(st, SIGNAL(fileScanned(QString)), m_dispatch, SLOT(fileAdded(QString)));
                connect(st, SIGNAL(filesScanned(QStringList)), m_dispatch, SLOT(filesAdded(QStringList)));
                connect(st, SIGNAL(finished()), st, SLOT(deleteLater()));
                st->start();
                QThread *dt = new QThread;
                DirWatch *dw = new DirWatch(dir);
                dw->moveToThread(dt);
                connect(this, SIGNAL(watchDir()), dw, SLOT(watchDir()));
                connect(dw, SIGNAL(fileAdded(QString)), m_dispatch, SLOT(dispatchFile(QString)));
                connect(dw, SIGNAL(fileRemoved(QString)), m_dispatch, SLOT(onFileRemoved(QString)));
                connect(dw, SIGNAL(fileRenamed(QString,QString)), m_dispatch, SLOT(onFileRenamed(QString,QString)));
                connect(dt, SIGNAL(finished()), dw, SLOT(deleteLater()));
                connect(dt, SIGNAL(finished()), dt, SLOT(deleteLater()));
                dt->start();
                emit watchDir();
            }
        }
    }
}

void DcmWatcher::startDcmWatch()
{
    setupDb();
    startDeamon();
    readDirs();
}
